<?php
/**
 * Created by PhpStorm.
 * User: sunbo
 * Date: 2019/7/19
 * Time: 11:44 AM
 */

namespace app\index\controller\sdk_utils;
class RsaEncrypt
{
    public $citpayPublicKey;

    public $citpayrsaPublicKey;

    public $mallRsaPrivateKeyFilePath;

    //  public $mallRsaPublicKeyFilePath;

    public $rsaPrivateKey;


    public function generateSign($params, $signType = "RSA2") {
        return $this->sign($this->getSignContent($params), $signType);
    }

    public function rsaSign($params, $signType = "RSA2") {
        return $this->sign($this->getSignContent($params), $signType);
    }

    protected function sign($data, $signType = "RSA2") {
        if($this->checkEmpty($this->mallRsaPrivateKeyFilePath)){
            $priKey=$this->rsaPrivateKey;
            $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
                wordwrap($priKey, 64, "\n", true) .
                "\n-----END RSA PRIVATE KEY-----";
        }else {
            $priKey = file_get_contents($this->mallRsaPrivateKeyFilePath);
            $res = openssl_get_privatekey($priKey);
        }
        ($res) or die('您使用的私钥格式错误，请检查RSA私钥配置');

        if ("RSA2" == $signType) {
            /*
            var_dump($data);
            echo "<hr>";
            var_dump($res);
            echo "<hr>";
            var_dump($sign);
            echo "<hr>";*/
            openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
        } else {
            openssl_sign($data, $sign, $res);
        }

        if(!$this->checkEmpty($this->mallRsaPrivateKeyFilePath)){
            openssl_free_key($res);
        }
        $sign = base64_encode($sign);
        return $sign;
    }


    /** rsaCheckV1 & rsaCheckV2
     *  验证签名
     *  在使用本方法前，必须初始化RsaEncrypt且传入公钥参数。
     *  公钥是否是读取字符串还是读取文件，是根据初始化传入的值判断的。
     **/
    public function rsaCheckV1($params, $rsaPublicKeyFilePath,$signType='RSA2') {
        $sign = $params['sign'];
        // $params['sign_type'] = null;
        $params['sign'] = null;
        $message = $params["message"];
        $params["message"] = null;
        $params["message"] =  $message;
        return $this->verify($this->getSignContent($params), $sign, $rsaPublicKeyFilePath,$signType);
    }
    public function rsaCheckCallback($params, $rsaPublicKeyFilePath,$signType='RSA2') {
        $sign = $params['sign'];
        $params['sign'] = null;
        return $this->verify($this->getSignContent($params), $sign, $rsaPublicKeyFilePath,$signType);
    }
    public function rsaCheckV2($params, $rsaPublicKeyFilePath, $signType='RSA') {
        $sign = $params['sign'];
        $params['sign'] = null;
        return $this->verify($this->getSignContent($params), $sign, $rsaPublicKeyFilePath, $signType);
    }

    function verify($data, $sign, $rsaPublicKeyFilePath, $signType = 'RSA2') {
        if( !$this->checkEmpty($this->citpayPublicKey)){
            $pubKey= $this->citpayPublicKey;
            $res = "-----BEGIN PUBLIC KEY-----\n" .
                wordwrap($pubKey, 64, "\n", true) .
                "\n-----END PUBLIC KEY-----";
        }else {
            //读取公钥文件
            $pubKey = file_get_contents($rsaPublicKeyFilePath);
            // $pubKey =  $this->citpayPublicKey ;
            //转换为openssl格式密钥
            $res = openssl_get_publickey($pubKey);

        }
        // var_dump($res);
        ($res) or die('citpay平台RSA公钥错误。请检查公钥文件格式是否正确');
        //调用openssl内置方法验签，返回bool值
        $result = FALSE;
        if ("RSA2" == $signType) {
            //var_dump($data);
            $result = (openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256)===1);
        } else {
            $result = (openssl_verify($data, base64_decode($sign), $res)===1);
        }
        if($this->checkEmpty($this->citpayPublicKey)) {
            //释放资源
            openssl_free_key($res);
        }
        return $result;
    }


    public function getSignContent($params) {
        ksort($params);

        $stringToBeSigned = "";
        $i = 0;
        foreach ($params as $k => $v) {
            if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {

                // 转换成目标字符集
                //  $v = $this->characet($v, $this->postCharset);

                if ($i == 0) {
                    $stringToBeSigned .= "$k" . "=" . "$v";
                } else {
                    $stringToBeSigned .= "&" . "$k" . "=" . "$v";
                }
                $i++;
            }
        }

        unset ($k, $v);
        return $stringToBeSigned;
    }


    /**
     * 校验$value是否非空
     *  if not set ,return true;
     *    if is null , return true;
     **/
    protected function checkEmpty($value) {
        if (!isset($value))
            return true;
        if ($value === null)
            return true;
        if (trim($value) === "")
            return true;
        return false;
    }


}